import logging
from deepdiff import DeepDiff  # 需要安装：pip install deepdiff

logger = logging.getLogger(__name__)


class AssertUtil:
    @staticmethod
    def assert_status_code(response, expected_code):
        """断言响应状态码"""
        actual_code = response.status_code
        assert actual_code == expected_code, \
            f"状态码错误：预期{expected_code}，实际{actual_code}"
        logger.info(f"状态码断言通过：{actual_code} == {expected_code}")

    @staticmethod
    def assert_json_key(response, key):
        """断言JSON响应中存在指定键"""
        json_data = response.json()
        assert key in json_data, f"响应中不存在键：{key}"
        logger.info(f"键存在断言通过：{key}")

    @staticmethod
    def assert_json_value(response, key, expected_value):
        """断言JSON响应中指定键的值"""
        json_data = response.json()
        AssertUtil.assert_json_key(response, key)  # 复用键存在断言
        actual_value = json_data[key]
        assert actual_value == expected_value, \
            f"键{key}的值错误：预期{expected_value}，实际{actual_value}"
        logger.info(f"键{key}值断言通过：{actual_value} == {expected_value}")

    @staticmethod
    def assert_json_structure(response, expected_structure):
        """
        断言JSON响应结构（支持嵌套）
        :param expected_structure: 预期结构，例如：{"code": int, "data": {"token": str}}
        """
        json_data = response.json()
        diff = DeepDiff(json_data, expected_structure, ignore_order=True)
        assert not diff, f"响应结构不匹配：{diff}"
        logger.info("响应结构断言通过")

    @staticmethod
    def assert_response_contains(response, expected_content):
        """断言响应文本包含指定内容（适用于非JSON响应）"""
        response_text = response.text
        assert expected_content in response_text, \
            f"响应不包含预期内容：{expected_content}，实际响应：{response_text}"
        logger.info(f"响应包含内容断言通过：{expected_content}")

    @staticmethod
    def assert_json_contains(response, expected_dict):
        """断言JSON响应包含指定键值对（部分匹配）"""
        json_data = response.json()
        # 递归检查预期字典是否是响应字典的子集
        def is_subset(subset, superset):
            if not isinstance(subset, dict) or not isinstance(superset, dict):
                return subset == superset
            return all(
                key in superset and is_subset(val, superset[key])
                for key, val in subset.items()
            )
        assert is_subset(expected_dict, json_data), \
            f"响应JSON不包含预期键值对：{expected_dict}，实际响应：{json_data}"
        logger.info(f"响应包含键值对断言通过：{expected_dict}")